package cd.cdyb.sms.service.impl;

import cd.cdyb.sms.constant.RedissonConstant;
import cd.cdyb.sms.dao.CompanyDao;
import cd.cdyb.sms.dao.RechargeDao;
import cd.cdyb.sms.dao.SystemConfigDao;
import cd.cdyb.sms.domain.Company;
import cd.cdyb.sms.domain.Recharge;
import cd.cdyb.sms.domain.SystemConfig;
import cd.cdyb.sms.dto.PageResult;
import cd.cdyb.sms.dto.RechargeDto;
import cd.cdyb.sms.dto.query.RechargeQueryDto;
import cd.cdyb.sms.exception.BusinessException;
import cd.cdyb.sms.service.InventoryService;
import cd.cdyb.sms.service.RechargeService;
import cd.cdyb.sms.service.RedisService;
import cd.cdyb.sms.utils.BeanUtilPlus;
import cd.cdyb.sms.utils.CacheUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author lin
 * @since 2024-05-16
 */
@Service
public class RechargeServiceImpl implements RechargeService {

    @Resource
    private RechargeDao rechargeDao;

    @Resource
    private CompanyDao companyDao;

    @Resource
    private InventoryService inventoryService;

    @Resource
    private RedisService redisService;

    public static final String ORDER_NUMBER = "number";

    @Resource
    private SystemConfigDao systemConfigDao;

    @Resource
    private RedissonClient redisson;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertRecharge(RechargeDto rechargeDto) throws BusinessException {
        RLock lock = redisson.getLock(RedissonConstant.SYSTEM_CONFIG_LOCK);
        lock.lock();
        try {
            Company company = companyDao.selectById(rechargeDto.getCompanyId());
            if (Objects.isNull(company)) {
                throw new BusinessException("未查询到该公司");
            }
            SystemConfig systemConfig = systemConfigDao.selectOne(new LambdaQueryWrapper<>());
            if (Objects.isNull(systemConfig)) {
                throw new BusinessException("未查询到配置信息");
            }
            LambdaUpdateWrapper<SystemConfig> wrapper = new LambdaUpdateWrapper<>();
            if (5 == rechargeDto.getRechargeType()) {
                if (systemConfig.getMarketingCount() < rechargeDto.getRechargeQuantity()) {
                    throw new BusinessException("系统营销短信余额不足");
                }
                wrapper.set(SystemConfig::getMarketingCount, systemConfig.getMarketingCount() - rechargeDto.getRechargeQuantity());
            } else if (6 == rechargeDto.getRechargeType()) {
                if (systemConfig.getIndustryCount() < rechargeDto.getRechargeQuantity()) {
                    throw new BusinessException("系统行业短信余额不足");
                }
                wrapper.set(SystemConfig::getIndustryCount, systemConfig.getIndustryCount() - rechargeDto.getRechargeQuantity());
            }
            Long number = redisService.vIncrement(CacheUtils.CacheName.RECHARGE_ORDER_NUMBER, ORDER_NUMBER, 1L);
            Recharge recharge = BeanUtilPlus.copyAs(rechargeDto, Recharge.class);
            recharge.setCompanyName(company.getCompanyName());
            recharge.setRechargeTime(LocalDateTime.now());
            recharge.setOrderNumber("CZ" + String.format("%06d", number));
            rechargeDao.insert(recharge);

            systemConfigDao.update(null, wrapper);

            //增加库存
            inventoryService.increaseInventory(company.getCompanyKey(), rechargeDto.getRechargeQuantity(), rechargeDto.getRechargeType());
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        } finally {
            lock.unlock();
        }
    }

    @Override
    public PageResult<RechargeDto> findRechargePageWithClient(RechargeQueryDto rechargeQueryDto) {
        Page<Recharge> page = new Page<>(rechargeQueryDto.getPageNo(), rechargeQueryDto.getPageSize());
        LambdaQueryWrapper<Recharge> wrapper = new LambdaQueryWrapper<>();
        if (Objects.nonNull(rechargeQueryDto.getCompanyId())) {
            wrapper.eq(Recharge::getCompanyId, rechargeQueryDto.getCompanyId());
        }
        if (StringUtils.isNotBlank(rechargeQueryDto.getOrderNumber())) {
            wrapper.like(Recharge::getOrderNumber, rechargeQueryDto.getOrderNumber());
        }
        if (Objects.nonNull(rechargeQueryDto.getStartTime()) && Objects.nonNull(rechargeQueryDto.getEndTime())) {
            wrapper.between(Recharge::getRechargeTime, rechargeQueryDto.getStartTime(), rechargeQueryDto.getEndTime());
        }
        wrapper.orderByDesc(Recharge::getRechargeTime);
        Page<Recharge> rechargePage = rechargeDao.selectPage(page, wrapper);
        List<RechargeDto> rechargeDtoList = BeanUtilPlus.copyAs(rechargePage.getRecords(), RechargeDto.class);
        return new PageResult<>(rechargeQueryDto.getPageNo(), rechargeQueryDto.getPageSize(), rechargeDtoList, rechargePage.getTotal());
    }

    @Override
    public void invoice(RechargeDto rechargeDto) throws BusinessException {
        if (StringUtils.isBlank(rechargeDto.getInvoiceNumber())) {
            throw new BusinessException("发票编号不能为空");
        }
        Recharge recharge = rechargeDao.selectById(rechargeDto.getRechargeId());
        if (Objects.isNull(recharge)) {
            throw new BusinessException("未查询到充值记录");
        }
        if (BooleanUtils.isTrue(recharge.getWhetherInvoice())) {
            throw new BusinessException("当前充值记录已开票");
        }
        LambdaUpdateWrapper<Recharge> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(Recharge::getWhetherInvoice, Boolean.TRUE)
                .set(Recharge::getInvoiceNumber, rechargeDto.getInvoiceNumber())
                .set(Recharge::getUpdateTime, LocalDateTime.now())
                .eq(Recharge::getRechargeId, recharge.getRechargeId());
        rechargeDao.update(null, wrapper);

    }
}
